#pragma once

#include <QMainWindow>
#include <QTcpServer>
#include <QLabel>
#include <QMouseEvent>
#include <QPushButton>
#include "card.h"
#include "labeledCard.h"
#include "cardQLabel.h"
#include "userqlabel.h"
#include "cardOnShowQLabel.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void init();                        // 重开游戏的时候进行再次初始化
    void end(bool);                     // 结束游戏的时候的处理
    void beginGame();                   // 开始游戏了，包括发牌，传递信息，并开始叫地主
    void dealPlayer(int);               // 处理三个玩家的请求的总接口
    void disconnect(int);               // 客户端断线的处理
    void dealForReady(int);             // 在准备阶段对用户信息作出处理
    void dealWaiting(int);              // 清空在等待进入房间时的请求，以免以后重复接受
    void dealDiZhu(bool);               // 处理谁要响应地主了，并作出相应动作
    void reshowCard(int);               // 响应卡牌被点击，让它向上移动一点
    void hideBuChu();

    void initForClient();               // 作为客户端的初始化程序

signals:

public slots:
    void receiveNewConnect();
    void dealClient1(){dealPlayer(1);}
    void dealClient2(){dealPlayer(2);}
    void clientDisconnect1(){disconnect(0);}
    void clientDisconnect2(){disconnect(1);}
    void beginGameSlot(){beginGame();}
    void jiaoDiZhu();
    void buJiao();
    void chuPaiSlot();
    void buChuSlot();
    void restartSlot();
    void restartReally();
    void quitSlot(){exit(0);}
    void startConnectSlot();

    void connectForClient();            // 作为客户端的连接socket程序
    void connectedForClient();          // 连接上服务器端就显示准备的按钮
    void readyForClient();              // 发是否准备好的信息
    void disconnectForClient();         // 客户端断线
    void jiaoDiZhuForClient();
    void buJiaoForClient();
    void dealAllForClient();
    void dealForDiZhu();
    void chuPaiForClient();
    void buChuForClient();
    void restartForClient();

private:
    // 游戏窗口及各种组件
    Ui::MainWindow *ui;
    ClientQLabel* mainLabel;          // 当前玩家的界面
    ClientQLabel* playerLabels[2];    // 两个玩家的显示界面
    QLabel* textOnShow;               // 当前显示的一些文字提示

    const int width=1000;            // 游戏窗口的宽度
    const int height=600;            // 游戏窗口的高度
    const int playerLabelWidth=200;  // 玩家信息框的宽度
    const int playerLabelHeight=300; // 玩家信息框的高度
    const int playerPadding=30;      // 玩家信息框和游戏窗口边界的距离
    const int cardWidth=90;          // 卡牌的宽度
    const int cardHeight=120;        // 卡牌的高度
    const int cardPadding=20;        // 卡牌和边框的距离
    const int beginForDiZhuCards=300;// 地主牌显示的开始处
    const int cardHigherDistance=20; // 选中的牌比原来的牌上移的位置
    const int buttonWidth=240;       // 按钮的宽度
    const int buttonHeight=70;       // 按钮的高度
    const int buttonPaddingTop=350;  // 按钮距离顶部的距离
    const int buttonPadding=20;      // 并排的按钮之间的距离
    const int textWidth=240;         // 文字区域的宽度
    const int textHeight=70;         // 文字区域的高度
    const int textPaddingTop=400;    // 文字区域距离顶部多少

    QPushButton* startConnect=nullptr;      // 服务端开始连接的按钮

    QPushButton* beDiZhu=nullptr;           // 叫地主的按钮
    QPushButton* notDiZhu=nullptr;          // 不叫地主的按钮

    QPushButton* chuPai=nullptr;    // 出牌的按钮
    QPushButton* buChu=nullptr;     // 不出的按钮

    QPushButton* restart=nullptr;   // 重开的按钮
    QPushButton* quit=nullptr;      // 退出的按钮

    QTcpServer* server;         // 作为服务器的server
    QTcpSocket* clients[2];     // 作为服务器和两位玩家通信的socket
    // 由于可以选择是否做服务器，以上两个在init()和end()构造和析构

    QTcpSocket* client=nullptr; // 作为客户端的socket
    QPushButton* connectButton=nullptr;// 做客户端时选择是否连接的按钮
    QPushButton* readyButton=nullptr;// 是否准备好
    int index_client;           // 客户端自己的序号
    bool another_ready;         // 另一个客户端有没有准备好
    bool another;               // 有没有另一个客户端连上了
    bool readied;               // 自己的状态是准备好了吗

    const int port =9000;       // 连接的端口
    int playerIndex;            // 现在正在进行的玩家序号
    int whoBegin;               // 是从谁开始出的
    int dizhu;                  // 地主是哪位玩家了
    int playerLast;             // 上次出牌的是谁

    // 用于显示现在在什么阶段了
    enum {
        waiting,                // 等人加入房间
        for_ready,              // 等大家点击是否准备好
        for_dizhu,              // 叫地主阶段
        gaming,                 // 游戏中
        ended,                  // 游戏已经结束了
    }state;

    bool winner_dizhu;          // 哪边赢了

    bool* diZhu=new bool[3];    // 不同玩家叫地主的时候作出了什么选择
    bool connected[2];          // 不同的玩家有没有连上
    bool is_ready[3];           // 不同的玩家有没有准备好【注：一开始没想到本身是默认准备好的，所以写了3】
    bool can_restart[3];        // 不同的玩家是否决定重开了
    std::vector<Card> cards;    // 现在的手牌
    std::vector<LabeledCard> card_labels;// 由上面生成的带label的牌
    Card dizhu_cards[3];        // 地主牌
    LabeledCard* dizhu_card_labels[3];// 地主牌的label
    CardOnShowQLabel* centerCards=nullptr;// 中间展示的上家出的牌

    void check_for_ready();     // 检查是否都准备好了，如果有了就开始游戏
    void distribute_cards();    // 发牌函数，包括三张地主牌和三个玩家的牌
    void show_dizhu_cards_hidden();// 以背面向上的形式显示出地主牌
    void show_my_cards();       // 展示现在cards有的卡牌
    void player_next();         // 按一圈的顺序给playerIndex进行自增
    void addDiZhuCards();       // 把地主牌加到地主手上
    void startGame();           // 服务端使用，需要负责改变state，并向客户端发送游戏开始的通知
    void awakePlayer();         // 提醒现在要出的用户出牌了，不负责playerIndex后滚
    void setupGamingUI();       // 把显示叫不叫地主的弄好；显示农民和地主字样
    void checkGameWin();        // 检查游戏赢了没

    Cards* lastCards=nullptr;   // 现在留存的招式
};
